package jar;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.swing.JOptionPane;
import jode.decompiler.Decompiler;

/*
 * @author erjot
 *
 * example
 *
 * JarFile j = new JarFile("C:\\Users\\erjot\\DCompiler.jar");
 * j.decompile("C:\\Users\\erjot\\java_example");
 *
 * W konstruktorze jako argument podajemy sciezke do pliku z Jarem.
 *
 * W funkcji decompile() argumentem jest ścieżka do folderu gdzie ma zapisać
 * rozpakowanego jara. Jezeli sciezka nie istnieje katalogi zostana utworzone
 *
 * */

public class JarFile extends Thread{

	private Enumeration entries;
	private String pathToJar;
	private String pathToSave;
        private String nonCompiledClasses = "";
	
	//-----------------------------------------------------------------------
	public JarFile(String pathToJar){
		ZipFile zf;
		try {
			if(pathToJar.endsWith(".jar")) 
                        {
                            zf = new ZipFile(pathToJar);
                            this.entries = zf.entries();
                        }
			this.pathToJar = pathToJar;
				
		} catch (IOException e) {
			e.printStackTrace();
		}	
	}
	
	//-----------------------------------------------------------------------
	public String getClassNames(){
		String contents = "";
		while (this.entries.hasMoreElements()) {
			ZipEntry ze = (ZipEntry) entries.nextElement();
			if(ze.getName().endsWith("class") && !ze.getName().contains("$"))
				contents+=ze.getName()+"\n";
		}
		return contents;
	}
	
	//-----------------------------------------------------------------------
	public void decompile(String pathToSave){
		if(!pathToSave.endsWith("/")) pathToSave+="/";
		this.pathToSave = pathToSave;
		this.start();
	}
	
	//-----------------------------------------------------------------------
	public void convertFromJar(String ClassName) throws IOException{

                (new File(this.pathToSave + pathToJar.substring(pathToJar.lastIndexOf("\\")+1, pathToJar.length()-4))).mkdirs();

		//tworzenie folderow --------------------------
		if(ClassName.contains("/")){
			String strManyDirectories = this.pathToSave + pathToJar.substring(pathToJar.lastIndexOf("\\")+1, pathToJar.length()-4) + "\\" + ClassName.substring(0, ClassName.lastIndexOf("/"));
			(new File(strManyDirectories)).mkdirs();
		}
		
		BufferedWriter bufferedWriter = null;
		(new File(this.pathToSave)).mkdir();
		if( ClassName.length()>7)
		bufferedWriter = new BufferedWriter(new FileWriter(this.pathToSave + pathToJar.substring(pathToJar.lastIndexOf("\\")+1, pathToJar.length()-4) + "\\" + ClassName.substring(0, ClassName.length()-6) + ".java"));
		
		Decompiler d = new Decompiler();
		d.setClassPath(this.pathToJar);
			
		try {
			d.setOption("verify", "off");
				d.decompile(ClassName.replace('/', '.').substring(0, ClassName.length()-6), bufferedWriter, null);
				System.out.println("Przekonwertowano " + ClassName.replace('/', '.').substring(0, ClassName.length()-6));
			
		} catch (IOException e) {
			nonCompiledClasses += ClassName + "\n";
		}
		
	}

        //zwraca liste klas których nie udało się zdekompilować
	public String getNonCompiledClasses(){
		return nonCompiledClasses;
	}

        //----------------------------------------------------------------------
        //usuwanie plikow

        //funkcja czysci zawartosc katalogu do ktorego prowadzi sciezka podana jako parametr,
        //mozna podac null wtedy jako usuwana jest zawartosc folderu deompiled_classes
        public void clearDirectory(String sciezka){

                if(sciezka==null) sciezka = "decompiled_classes";
		File katalog = new File(sciezka);
                if(katalog.isDirectory()){
                    String lista[] = katalog.list();
                    for(int i=0; i<lista.length; i++)
                    {
                            File plik = new File(sciezka + "\\" +lista[i]);
                            if(plik.isDirectory()) {
                                clearDirectory(sciezka + "\\" + lista[i]);
                                plik.delete();
                            }else
                            {
                                plik.delete();
                            }
                    }
                }
	}

        //----------------------------------------------------------------------
        //listowanie plikow

        //funkcja dodaje do wektora sciezek zawartosci kolejnych katalogow
        private void addFileToVector(String sciezka, Vector<String> listaPlikow){

		File katalog = new File(sciezka);
		String lista[] = katalog.list();
		for(int i=0; i<lista.length; i++)
		{
			File plik = new File(sciezka + "\\" +lista[i]);
			if(plik.isDirectory()) {
				addFileToVector(sciezka + "\\" + lista[i], listaPlikow);
			}else
			{
				if(lista[i].endsWith(".java"))
                                    listaPlikow.add(sciezka+ "\\" + lista[i]);
			}
		}
	}

        //zwraca list sciezek do plikow java analizowanej aplikacji
        public Vector<String> getFileList(String path) throws InterruptedException{
            join();
            Vector<String> fileList = new Vector<String>();
            String analyzedDirectory = "";

            if(path.endsWith(".jar")){
                analyzedDirectory = pathToSave.replaceAll("/", "");
                addFileToVector(analyzedDirectory, fileList);
            }
            else fileList.add(path);//analyzedDirectory = path;
            System.out.println(fileList);
            
            return fileList;
        }

        //dekompilujemy w nowym wątku
	public void run(){
		while (this.entries.hasMoreElements()) {
			ZipEntry ze = (ZipEntry) entries.nextElement();
			if(ze.getName().endsWith("class") && !ze.getName().contains("$"))
				try {
					this.convertFromJar(ze.getName());

				} catch (Exception e) {
					e.printStackTrace();
				}
		}

		if(!nonCompiledClasses.equals("")) JOptionPane.showMessageDialog(null, "Nie przekonwertowano następujących klas:\n" + this.getNonCompiledClasses(),"Błąd konwersji",  JOptionPane.ERROR_MESSAGE);

	}
	
}
